package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
)

func main() {
	//baseError()
	//createError()
	//_, myError := myErrorTest(1)
	//if myError != nil {
	//	fmt.Println(myError.Error())
	//}
	//err := returnError(2)
	//if err != nil {
	//	fmt.Println(err)
	//}
	//panicTest(1)
	//createError()
	//deferParam()

	//i := deferReturn()
	//fmt.Println("main i:", i)//100
	//fmt.Println("main g:", g)//200

	j := deferReturn2()
	fmt.Println("main j:", j) //200
	fmt.Println("main g:", g) //100
}

var g = 100

func deferReturn() int {
	defer func() {
		g = 200
	}()
	fmt.Println("defer g:", g) //100
	return g
}

// return 不是一个原子操作
// 1.返回值保存在栈上 2. 执行 defer  3. 函数返回
func deferReturn2() (r int) {
	r = g
	defer func() {
		r = 200
	}()
	r = 0
	return r
}

// defer 中的参数为预计算，不会等到执行完毕后才传值
func deferParam() {
	a := 1
	defer func(a int) {
		fmt.Println("defer a :", a) // 打印 2
	}(a + 1) // 在调用到此的时候，就已经将 a+1计算完毕，才将 defer 入栈
	a = 99
}

func baseError() {
	file, err := ioutil.ReadFile("test.txt")
	if err != nil {
		ioutil.WriteFile("test2.txt", file, os.ModeAppend)
	} else {
		fmt.Println("no error")
	}
}
func createError() {
	err := errors.New("This is an error")
	fmt.Println(err)

	err = fmt.Errorf("your name %v is not valid", "xiaozhu")
	fmt.Println(err)
}

func returnError(i int) error {
	if i%2 == 0 {
		return errors.New("i:" + strconv.Itoa(i) + " is not 奇数")
	}
	return nil
}

/**
可以理解为Java的Throw，可直接终止程序
*/
func panicTest(i int) {
	defer func() {
		if er := recover(); er != nil {
			fmt.Println("出错啦..")

		}
	}()
	if i%2 != 0 {
		panic("i为奇数，程序终止")
	}
	fmt.Println("go on ")
}

/**
Go语言中错误是一个值，error接口中只有一个Error方法，返回一个字符串
*/
//自定义error
type MyError struct {
	msg       string
	errorType int
}

// 实现Error接口，这样就可以把MyError作为error类型来使用了
func (myError *MyError) Error() string {
	return strconv.Itoa(myError.errorType) + "->" + myError.msg
}
func myErrorTest(i int) (int, error) {
	if i%2 == 0 {
		return i, nil
	} else {
		myError := MyError{
			msg:       "不可整除2",
			errorType: 1,
		}
		return i, &myError
	}
}
